home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / fmsdisk / fms.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  11KB  |  527 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  FMS.C
  9.  *
  10.  *  File Disk Device (fmsdisk.device)
  11.  *
  12.  *  Simulates a trackdisk by using a large file to hold the 'blocks'.
  13.  */
  14.  
  15. #include "defs.h"
  16.  
  17. Prototype DevCall NDev *DevInit(register __a0 APTR);
  18. Prototype DevCall NDev *DevOpen(register __d0 long, register __a1 IOB *, register __d1 long);
  19. Prototype APTR DevExpunge(void);
  20. Prototype APTR DevClose(register __a1 IOB *);
  21. Prototype APTR DevReserved(void);
  22. Prototype void DevBeginIO(register __a1 IOB *iob);
  23. Prototype void DevAbortIO(register __a1 IOB *iob);
  24. Prototype void SynchroMsg(UWORD, NDUnit *);
  25. Prototype __geta4 void CoProc(void);
  26. Prototype void ExtendSize(NDUnit *, long);
  27. Prototype void FlushCache(void);
  28. Prototype void GetUnitName(int, char *);
  29.  
  30. extern struct Library *SysBase;
  31. struct DosLibrary *DOSBase    = NULL;
  32.  
  33. NDev *DevBase;
  34. APTR DevSegment;
  35. PORT *FProc;
  36. PORT FPort;
  37.  
  38. #ifdef DEBUG
  39. long DbFH;
  40. #endif
  41.  
  42. NDUnit *CacheUnit;
  43. long    CacheLen;
  44. char    CacheBuf[32768];    /*    32K buffer  */
  45.  
  46. /*
  47.  *  Init, segment in A0 (registered args), arg must be declared as a pointer
  48.  */
  49.  
  50. DevCall
  51. NDev *
  52. DevInit(register __a0 APTR seg)
  53. {
  54.     static func_ptr DevVectors[] = {
  55.     (func_ptr)DevOpen,
  56.     (func_ptr)DevClose,
  57.     (func_ptr)DevExpunge,
  58.     (func_ptr)DevReserved,
  59.     (func_ptr)DevBeginIO,
  60.     (func_ptr)DevAbortIO,
  61.     (func_ptr)-1
  62.     };
  63.     NDev *db;
  64.  
  65.     DevBase = db = (NDev *)MakeLibrary((long **)DevVectors,NULL,NULL,sizeof(NDev),NULL);
  66.     db->Lib.lib_Node.ln_Type = NT_DEVICE;
  67.     db->Lib.lib_Node.ln_Name = DeviceName;
  68.     db->Lib.lib_Flags = LIBF_CHANGED|LIBF_SUMUSED;
  69.     db->Lib.lib_Version = 1;
  70.     db->Lib.lib_IdString= (APTR)IdString;
  71.  
  72.     DevSegment = seg;
  73.     AddDevice((DEV *)db);
  74.     return(db);
  75. }
  76.  
  77. /*
  78.  *  open device
  79.  *
  80.  *    unitnum:    D0
  81.  *    iob:        A1
  82.  *    flags:        D1
  83.  *
  84.  *  have dummy pointer before iob so iob gets assigned A1 instead of A0
  85.  *  for registered args interface.
  86.  */
  87.  
  88. DevCall
  89. NDev *
  90. DevOpen(register __d0 long unitnum,
  91.     register __a1 IOB *iob,
  92.     register __d1 long flags
  93.        )
  94. {
  95.     NDev *nd = DevBase;
  96.     NDUnit *unit = &nd->Unit[unitnum];
  97.  
  98.     if (++nd->Lib.lib_OpenCnt == 1) {
  99.     FProc = CreateProc("FMS-Dummy", 0, (long)DUMmySeg >> 2, 8192);
  100.     FPort.mp_SigBit = SIGBREAKB_CTRL_D;    /*  port init */
  101.     FPort.mp_SigTask= FProc->mp_SigTask;
  102.     FPort.mp_Flags = PA_SIGNAL;
  103.     NewList(&FPort.mp_MsgList);
  104.     }
  105.  
  106.     if (++unit->OpenCnt == 1)
  107.     SynchroMsg(CMD_OPENUNIT, unit);
  108.  
  109.     nd->Lib.lib_Flags &= ~LIBF_DELEXP;
  110.     iob->io_Unit = (struct Unit *)unit;
  111.     iob->io_Error = 0;
  112.     return(nd);
  113. }
  114.  
  115. /*
  116.  *  expunge device, no arguments
  117.  */
  118.  
  119. APTR
  120. DevExpunge(void)
  121. {
  122.     NDev *nd = DevBase;
  123.     APTR dseg = DevSegment;
  124.  
  125.     if (dseg == NULL)
  126.     Alert(24);
  127.     if (nd->Lib.lib_OpenCnt) {
  128.     nd->Lib.lib_Flags |= LIBF_DELEXP;
  129.     return(NULL);
  130.     }
  131.     Remove((NODE *)nd);
  132.     FreeMem((char *)nd - nd->Lib.lib_NegSize, nd->Lib.lib_NegSize + nd->Lib.lib_PosSize);
  133.     ADevExpunge();
  134.     return(dseg);
  135. }
  136.  
  137. /*
  138.  *  device close.  Dummy pointer before iob so iob gets assigned A1
  139.  *
  140.  *    iob:    A1
  141.  */
  142.  
  143. DevCall
  144. APTR
  145. DevClose(register __a1 IOB *iob)
  146. {
  147.     NDev *nd = DevBase;
  148.  
  149.     {
  150.     NDUnit *unit = (NDUnit *)iob->io_Unit;
  151.     if (unit->OpenCnt && --unit->OpenCnt == 0)
  152.         SynchroMsg(CMD_CLOSEUNIT, unit);
  153.     }
  154.  
  155.     if (nd->Lib.lib_OpenCnt && --nd->Lib.lib_OpenCnt)
  156.     return(NULL);
  157.     if (FProc) {
  158.     SynchroMsg(CMD_KILLPROC, NULL);
  159.     FProc = NULL;
  160.     }
  161.     if (nd->Lib.lib_Flags & LIBF_DELEXP)
  162.     return(DevExpunge());
  163.     /*
  164.      *    close down resources
  165.      */
  166.     return(NULL);
  167. }
  168.  
  169. DevCall
  170. APTR
  171. DevReserved(void)
  172. {
  173.     return((APTR)0);
  174. }
  175.  
  176. DevCall
  177. void
  178. DevBeginIO(register __a1 IOB *iob)
  179. {
  180.     /*NDev *nd = DevBase;*/
  181.  
  182.     iob->io_Error = 0;
  183.     iob->io_Actual = 0;
  184.  
  185.     switch(iob->io_Command & ~TDF_EXTCOM) {
  186.     case CMD_INVALID:
  187.     iob->io_Error = IOERR_NOCMD;
  188.     break;
  189.     case CMD_RESET:
  190.     break;
  191.     case CMD_READ:
  192.     PutMsg(&FPort, &iob->io_Message);
  193.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  194.     iob = NULL;
  195.     break;
  196.     case CMD_WRITE:
  197.     PutMsg(&FPort, &iob->io_Message);
  198.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  199.     iob = NULL;
  200.     break;
  201.     case CMD_UPDATE:
  202.     PutMsg(&FPort, &iob->io_Message);
  203.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  204.     iob = NULL;
  205.     break;
  206.     case CMD_CLEAR:
  207.     break;
  208.     case CMD_STOP:
  209.     break;
  210.     case CMD_START:
  211.     break;
  212.     case CMD_FLUSH:
  213.     break;
  214.     case TD_MOTOR:        /*    motor,    no action   */
  215.     case TD_SEEK:        /*    seek,    no action   */
  216.     break;
  217.     case TD_FORMAT:        /*    format            */
  218.     PutMsg(&FPort, &iob->io_Message);
  219.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  220.     iob = NULL;
  221.     break;
  222.     case TD_REMOVE:        /*    not supported        */
  223.     iob->io_Error = IOERR_NOCMD;
  224.     break;
  225.     case TD_CHANGENUM:        /*    change count never changes  */
  226.     iob->io_Actual = 1;
  227.     break;
  228.     case TD_CHANGESTATE:    /*    0=disk in drive     */
  229.     iob->io_Actual = 0;
  230.     break;
  231.     case TD_PROTSTATUS:     /*    io_Actual -> 0 (rw) */
  232.     iob->io_Actual = 0;
  233.     break;
  234.     case TD_RAWREAD:        /*    not supported        */
  235.     case TD_RAWWRITE:
  236.     iob->io_Error = IOERR_NOCMD;
  237.     break;
  238.     case TD_GETDRIVETYPE:   /*    drive type?        */
  239.     iob->io_Actual = 0;
  240.     break;
  241.     case TD_GETNUMTRACKS:
  242.     iob->io_Actual = 0; /*    # of tracks?        */
  243.     break;
  244.     case TD_ADDCHANGEINT:   /*    action never taken  */
  245.     case TD_REMCHANGEINT:
  246.     break;
  247.     default:
  248.     iob->io_Error = IOERR_NOCMD;
  249.     break;
  250.     }
  251.     if (iob) {
  252.     if ((iob->io_Flags & IOF_QUICK) == 0)
  253.         ReplyMsg((MSG *)iob);
  254.     }
  255. }
  256.  
  257. DevCall
  258. void
  259. DevAbortIO(register __a1 IOB *iob)
  260. {
  261.  
  262. }
  263.  
  264.  
  265. /*
  266.  *  Server communications.  If we run out of memory, well, we retry
  267.  *  until memory is available.
  268.  */
  269.  
  270. void
  271. SynchroMsg(cmd, unit)
  272. UWORD cmd;
  273. NDUnit *unit;
  274. {
  275.     IOB Iob;
  276.  
  277.     do {
  278.     Iob.io_Message.mn_ReplyPort = CreatePort(NULL, 0);
  279.     Iob.io_Command = cmd;
  280.     Iob.io_Unit = (struct Unit *)unit;
  281.     } while (Iob.io_Message.mn_ReplyPort == NULL);
  282.  
  283.     PutMsg(&FPort, &Iob.io_Message);
  284.     WaitPort(Iob.io_Message.mn_ReplyPort);
  285.     DeletePort(Iob.io_Message.mn_ReplyPort);
  286. }
  287.  
  288. /*
  289.  *    SERVER SIDE (IS A PROCESS)
  290.  *
  291.  *    File name is:
  292.  */
  293.  
  294. __geta4 void
  295. CoProc(void)
  296. {
  297.     IOB *iob;
  298.     NDUnit *unit;
  299.     char buf[128];
  300.     char notdone = 1;
  301.  
  302.     Wait(SIGBREAKF_CTRL_D);     /*  wait for port init  */
  303.  
  304.     while (notdone) {
  305.     WaitPort(&FPort);
  306.     while (iob = (IOB *)GetMsg(&FPort)) {
  307.         unit = (NDUnit *)iob->io_Unit;
  308.  
  309. #ifdef DEBUG
  310.         if (DbFH) {
  311.         sprintf(buf, "Cmd %08lx/%04x @ %08lx Buf %08lx %04x\n",
  312.             unit, iob->io_Command, iob->io_Offset, iob->io_Data, iob->io_Length
  313.         );
  314.         Write(DbFH, buf, strlen(buf));
  315.         }
  316. #endif
  317.         /*
  318.          *    cache (increase OFS throughput)
  319.          */
  320.  
  321.         if (CacheLen && (iob->io_Command & ~TDF_EXTCOM) != CMD_WRITE)
  322.         FlushCache();
  323.  
  324.         switch(iob->io_Command & ~TDF_EXTCOM) {
  325.         case CMD_OPENUNIT:
  326.         GetUnitName(unit - &DevBase->Unit[0], buf);
  327.         unit->Fh = Open(buf, 1005);
  328.         if (unit->Fh == NULL) {
  329.             unit->Fh = Open(buf, 1006);
  330.             unit->Extended = 1;
  331.         }
  332. #ifdef DEBUG
  333.         if (DbFH) {
  334.             Write(DbFH, "OPEN ", 5);
  335.             Write(DbFH, buf, strlen(buf));
  336.             Write(DbFH, "\n", 1);
  337.         }
  338. #endif
  339.         if (unit->Fh) {
  340.             Seek(unit->Fh, 0L, 1);
  341.             unit->Size = Seek(unit->Fh, 0L, -1);
  342.         }
  343.         unit->Pos = -1;
  344.         break;
  345.         case CMD_CLOSEUNIT:
  346.         if (unit->Fh) {
  347.             Close(unit->Fh);
  348.             unit->Fh = NULL;
  349.         }
  350.         break;
  351.         case CMD_KILLPROC:
  352.         notdone = 0;
  353.         break;
  354.         case CMD_READ:
  355.         if (unit->Fh == NULL)
  356.             break;
  357.         if (iob->io_Offset + iob->io_Length > unit->Size)
  358.             ExtendSize(unit, iob->io_Offset + iob->io_Length);
  359.         if (unit->Pos != iob->io_Offset)
  360.             Seek(unit->Fh, iob->io_Offset, -1);
  361.         iob->io_Actual = Read(unit->Fh, (char *)iob->io_Data, iob->io_Length);
  362.         if (iob->io_Actual == iob->io_Length)
  363.             unit->Pos = iob->io_Offset + iob->io_Actual;
  364.         else
  365.             unit->Pos = -1;
  366.         break;
  367.         case CMD_WRITE:
  368.         /*
  369.          *  This causes file to be closed/reopened after
  370.          *  formatting.
  371.          */
  372.         if (unit->Extended && unit->Fh) {
  373.             FlushCache();
  374.             Close(unit->Fh);
  375.             GetUnitName(unit - &DevBase->Unit[0], buf);
  376.             unit->Fh = Open(buf, 1005);
  377.             unit->Extended = 0;
  378.         }
  379.         /* fall through */
  380.         case TD_FORMAT:
  381.         if (unit->Fh == NULL)
  382.             break;
  383.  
  384.         if (iob->io_Offset > unit->Size) {
  385.             FlushCache();
  386.             ExtendSize(unit, iob->io_Offset);
  387.         }
  388.         if (CacheUnit != unit) {
  389.             FlushCache();
  390.             CacheUnit = unit;
  391.         }
  392.         if (unit->Pos != iob->io_Offset) {
  393.  
  394.             /*
  395.              *    Handle case where a CMD_WRITE modifies a previously
  396.              *    cached write (occurs with OFS *a lot*)
  397.              */
  398.  
  399.             if (CacheLen) {
  400.             long ci = CacheLen - (unit->Pos - iob->io_Offset);
  401.             if (ci >= 0 && ci + iob->io_Length <= CacheLen) {
  402. #ifdef DEBUG
  403.                 if (DbFH)
  404.                 Write(DbFH, "XBACK\n", 5);
  405. #endif
  406.                 iob->io_Actual = iob->io_Length;
  407.                 movmem(iob->io_Data, CacheBuf + ci, iob->io_Length);
  408.                 break;
  409.             }
  410.             }
  411.             FlushCache();
  412.             Seek(unit->Fh, iob->io_Offset, -1);
  413.         }
  414.  
  415.         if (CacheLen + iob->io_Length > sizeof(CacheBuf))
  416.             FlushCache();
  417.         if (CacheLen + iob->io_Length <= sizeof(CacheBuf)) {
  418.             iob->io_Actual = iob->io_Length;
  419.             unit->Pos = iob->io_Offset + iob->io_Actual;
  420.             movmem(iob->io_Data, CacheBuf + CacheLen, iob->io_Actual);
  421.             CacheLen += iob->io_Actual;
  422.         } else {
  423.             if (CacheLen)
  424.             FlushCache();
  425.             iob->io_Actual = Write(unit->Fh, (char *)iob->io_Data, iob->io_Length);
  426.             if (iob->io_Actual == iob->io_Length)
  427.             unit->Pos = iob->io_Offset + iob->io_Actual;
  428.             else
  429.             unit->Pos = -1;
  430.         }
  431.         break;
  432.         default:
  433.         break;
  434.         }
  435.  
  436.         if (notdone == 0)       /*  forbid before falling through */
  437.         Forbid();           /*  and esp before replying       */
  438.         ReplyMsg(&iob->io_Message);
  439.     }
  440. #ifdef DEBUG
  441.     if (DbFH == NULL)
  442.         DbFH = Open("con:0/0/320/100/Debug", 1006);
  443. #endif
  444.     }
  445. #ifdef DEBUG
  446.     if (DbFH)
  447.     Close(DbFH);
  448. #endif
  449.     /* fall through to exit */
  450. }
  451.  
  452. void
  453. GetUnitName(int unitnum, char *buf)
  454. {
  455. BPTR envfile;
  456. LONG envlen;
  457. BOOL gotit = FALSE;
  458.  
  459. /* New - see if ENVIRONMENT variable FMSUnit<n> exists (ex. FMSUnit2)
  460.  * containing full path to file.
  461.  */
  462. sprintf(buf,"ENV:FMSUnit%d",unitnum);
  463. if(envfile = Open(buf,MODE_OLDFILE))
  464.     {
  465.     envlen = Read(envfile,buf,128-2);
  466.     if(envlen >= 0)
  467.     {
  468.     gotit = TRUE;
  469.     buf[envlen] = '\0';
  470.         if(buf[envlen-1]=='\n') buf[envlen-1] = '\n';
  471.     }
  472.     Close(envfile);
  473.     }
  474. /* Fallback to old FMS:Unit<n> name */
  475. if(!gotit)
  476.     {
  477.     sprintf(buf, "FMS:Unit%d", unitnum);
  478.     }
  479. }
  480.  
  481. /*
  482.  *  Extend the file size in 4K chunks
  483.  */
  484.  
  485. void
  486. ExtendSize(unit, offset)
  487. NDUnit *unit;
  488. long offset;
  489. {
  490.     long pos;
  491.     char *buf = AllocMem(EXT_CHUNK, MEMF_CLEAR|MEMF_PUBLIC);
  492.  
  493.     if (buf) {
  494.     if (unit->Extended == 0)
  495.         unit->Extended = 1;
  496.     Seek(unit->Fh, 0L, 1);
  497.     pos = Seek(unit->Fh, 0L, 0);
  498.     while (pos < offset) {
  499.         if (Write(unit->Fh, buf, EXT_CHUNK) != EXT_CHUNK)
  500.         break;
  501.         pos += EXT_CHUNK;
  502.     }
  503.     FreeMem(buf, EXT_CHUNK);
  504.     unit->Pos = -1;     /*    unknown */
  505.     }
  506. }
  507.  
  508. /*
  509.  *  flush sequential write cache
  510.  */
  511.  
  512. void
  513. FlushCache()
  514. {
  515.     NDUnit *unit = CacheUnit;
  516.  
  517. #ifdef DEBUG
  518.     if (DbFH)
  519.     Write(DbFH, "FLUSH\n", 6);
  520. #endif
  521.  
  522.     if (CacheLen) {
  523.     Write(unit->Fh, CacheBuf, CacheLen);
  524.     CacheLen = 0;
  525.     }
  526. }
  527.